package com.hfut.eeg.config;

import com.hfut.eeg.common.component.RestAuthenticationEntryPoint;
import com.hfut.eeg.common.component.RestfulAccessDeniedHandler;
import com.hfut.eeg.dto.User;
import com.hfut.eeg.filter.JwtAuthenticationTokenFilter;
import com.hfut.eeg.properties.SecurityProperties;
import com.hfut.eeg.service.AdminUserdetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.util.List;


/**
 * SpringSecurity的配置
 * Created by macro on 2018/4/26.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AdminUserdetailService userdetailService;

    /**
    * @Description: 核心环境配置
    * @author 梁琦
    * @date 2019-12-30 20:08
    * @throws
    */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .formLogin()
                .usernameParameter("userName")//用户登录用户名
                .passwordParameter("userPassword")//配置用户密码参数
                //.loginPage("/loginpage")
                //.failureUrl("/loginpage")
                .loginProcessingUrl("http://localhost:8080/user/login")//登录请求地址
//                .successForwardUrl("/appointmentpage")
                .and()
            .rememberMe()//配置记住我
                //.rememberMeParameter("remember-me")
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//配置过期秒数
                .userDetailsService(userdetailService)//使用其作为登录
                .rememberMeParameter("remember")
                .key("INTERNAL_SECRET_KEY")
                .and()
            .authorizeRequests()//排序会影响？？？  配置认证管理
                .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
                .permitAll()
                .antMatchers("/user/register","/report/**")
                .hasRole("ADMIN")
                .antMatchers("/Setup/*")
                .hasRole("ADMIN")
                .antMatchers("/report/*")
                .hasRole("USER")
                .anyRequest()
                .permitAll()
                .and()
            .csrf()
            .disable();

        // 禁用缓存
        //httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
    }

    @Override
    public void configure(WebSecurity web) {
        super.configure(web);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.jdbcAuthentication();
        auth.userDetailsService(new AdminUserdetailService());
    }

    /*@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }*/

    //配置密码加密
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /*@Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return username -> {
            User admin = adminService.getAdminByUsername(username);
            if (admin != null) {
                List<UmsPermission> permissionList = adminService.getPermissionList(admin.getId());
                return new AdminUserDetails(admin,permissionList);
            }
            throw new UsernameNotFoundException("用户名或密码错误");
        };
    }*/

    @Bean
    public UserDetailsService userDetailsService(){
        return new AdminUserdetailService();
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //这个bean作为实现RememberMe功能
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //注意，只运行一次就行，否则后续数据库会报错
        //tokenRepository.setCreateTableOnStartup(true);
        return  tokenRepository;
    }

}
